using System.Collections.Generic;
using System.Linq;
using Infinity.Common;
using Infinity.Common.Extensions;
using Infinity.Statements.Declare;
using Infinity.Statements.Program;
using Infinity.Statements.StatementFactory;

namespace Infinity.Statements.Utilities
{
	/// <summary>
	/// Scope manager
	/// </summary>
	public class ScopeManager : IScopeManager
	{
		/// <summary>
		/// Scopes
		/// </summary>
		protected Stack<IScope> Scopes { get; set; }

		/// <summary>
		/// Default constructor
		/// </summary>
		public ScopeManager()
		{
			Scopes = new Stack<IScope>();
		}

		/// <summary>
		/// Get variable from scopes by name
		/// </summary>
		public IVariableStatement GetVariable(string name)
		{
			name = Ensure.NotBlank(name).Trim();

			foreach (var scope in Scopes)
			{
				IVariableStatement variable;
				if (scope.Variables.TryGetValue(name, out variable))
					return variable;
			}

			return null;
		}

		/// <summary>
		/// It pops scope.
		/// </summary>
		public void RemoveScope()
		{
			Ensure.NotEmpty(Scopes);

			Scopes.Pop();
		}

		/// <summary>
		/// Get function from scopes by name
		/// </summary>
		public IProgramStatement GetFunction(string name)
		{
			name = Ensure.NotBlank(name).Trim();

			foreach (var scope in Scopes)
			{
				IProgramStatement result;
				if (scope.Functions.TryGetValue(name, out result))
					return result;
			}

			return null;
		}

		/// <summary>
		/// It returns the current scope.
		/// </summary>
		public IScope CurrentScope()
		{
			Ensure.NotNull(Scopes);
			if (!Scopes.Any())
				Error.ThrowException("Stack of scopes is empty!");

			return Scopes.Peek();
		}

		/// <summary>
		/// It creates a new scope for statement
		/// </summary>
		public IScope CreateScope(IStatement statement = null)
		{
			Ensure.NotNull(Scopes);
			var scope = new Scope
				            {
					            ScopeStatement = statement
				            };
			Scopes.Push(scope);
			return scope;
		}
	}
}